home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / CUGUK / COMMS / C101.ZIP / UUPC11XS.ZIP / UUCICO / DCPGPKT.C < prev    next >
C/C++ Source or Header  |  1992-11-21  |  57KB  |  1,628 lines

  1. /*
  2.    dcpgpkt.c
  3.  
  4.    Revised edition of dcp
  5.  
  6.    Stuart Lynne May/87
  7.  
  8.    Copyright (c) Richard H. Lamb 1985, 1986, 1987
  9.    Changes Copyright (c) Stuart Lynne 1987
  10.    Changes Copyright (c) Andrew H. Derbyshire 1989
  11.    Changes Copyright (c) Kendra Electronic Wonderworks 1990-1992
  12.  
  13.    Maintenance notes:
  14.  
  15.    25Aug87 - Allow for up to 7 windows - Jal
  16.    01Nov87 - those strncpy's should really be memcpy's! - Jal
  17.    11Sep89 - Raise TimeOut to 15 - ahd
  18.    30Apr90 - Add Jordon Brown's fix for short packet retries.
  19.              Reduce retry limit to 20                             ahd
  20.    22Jul90 - Change error retry limit from per host to per
  21.              packet.                                              ahd
  22.    22Jul90 - Add error message for number of retries exceeded     ahd
  23.    08Sep90 - Drop memmove to memcpy change supplied by Jordan
  24.              Brown, MS 6.0 and Turbo C++ agree memmove insures
  25.              no overlap
  26. */
  27.  
  28. /*
  29.  *      $Id: DCPGPKT.C 1.7 1992/11/21 05:55:11 ahd Exp $
  30.  *
  31.  *      $Log: DCPGPKT.C $
  32.  * Revision 1.7  1992/11/21  05:55:11  ahd
  33.  * Use single bit field for gopenpk flag bits, add debugging info
  34.  *
  35.  * Revision 1.6  1992/11/20  12:38:39  ahd
  36.  * Add additional flags to avoid prematurely ending init sequence
  37.  *
  38.  * Revision 1.5  1992/11/19  03:00:29  ahd
  39.  * drop rcsid
  40.  *
  41.  * Revision 1.4  1992/11/17  13:45:37  ahd
  42.  * Add comments from Ian Talyor
  43.  *
  44.  * Revision 1.3  1992/11/16  02:10:27  ahd
  45.  * Rewrite protocol initialize to insure full exchange of packets
  46.  *
  47.  */
  48.  
  49.  
  50. /* "DCP" a uucp clone. Copyright Richard H. Lamb 1985,1986,1987 */
  51.  
  52. /* 7-window "g" ptotocol */
  53.  
  54. /*--------------------------------------------------------------------*/
  55. /*    Thanks goes to John Gilmore for sending me a copy of Greg       */
  56. /*    Chesson's UUCP protocol description -- Obviously invaluable.    */
  57. /*    Thanks also go to Andrew Tannenbaum for the section on          */
  58. /*    Siding window protocols with a program example in his           */
  59. /*    "Computer Networks" book.                                       */
  60. /*--------------------------------------------------------------------*/
  61.  
  62. /*--------------------------------------------------------------------*/
  63. /*                        System include files                        */
  64. /*--------------------------------------------------------------------*/
  65.  
  66. #include <stdio.h>
  67. #include <string.h>
  68. #include <time.h>
  69. #include <stdlib.h>
  70. #include <ctype.h>
  71.  
  72. #ifdef __TURBOC__
  73. #include <mem.h>
  74. #include <alloc.h>
  75. #else
  76. #include <malloc.h>
  77. #endif
  78.  
  79. /*--------------------------------------------------------------------*/
  80. /*                    UUPC/extended include files                     */
  81. /*--------------------------------------------------------------------*/
  82.  
  83. #include "lib.h"
  84. #include "dcp.h"
  85. #include "dcpsys.h"
  86. #include "dcpgpkt.h"
  87. #include "hostable.h"
  88. #include "security.h"
  89. #include "ulib.h"
  90. #include "modem.h"
  91. #include "catcher.h"
  92.  
  93. /*--------------------------------------------------------------------*/
  94. /*                           Local defines                            */
  95. /*--------------------------------------------------------------------*/
  96.  
  97. #define PKTSIZE   MAXPACK
  98. #define MINPKT    32
  99.  
  100. #define HDRSIZE   6
  101. #define MAXTRY 4
  102.  
  103. #ifndef GDEBUG
  104. #define GDEBUG 4
  105. #endif
  106.  
  107. /*--------------------------------------------------------------------*/
  108. /*    Control whether some buffers are placed outside the default     */
  109. /*    data segment                                                    */
  110. /*--------------------------------------------------------------------*/
  111.  
  112. #ifdef __TURBOC__
  113. #define memavail  coreleft
  114. #else
  115. #define memavail  stackavail
  116. #endif
  117.  
  118. /*--------------------------------------------------------------------*/
  119. /*                     g-packet type definitions                      */
  120. /*--------------------------------------------------------------------*/
  121.  
  122. #define DATA   0
  123. #define CLOSE  1
  124. #define NAK    2
  125. #define SRJ    3
  126. #define ACK    4
  127. #define INITC  5
  128. #define INITB  6
  129. #define INITA  7
  130.  
  131. #define POK    -1
  132.  
  133. #define MAXWINDOW 7
  134. #define NBUF   8              /* always SAME as MAXSEQ ? */
  135. #define MAXSEQ 8
  136.  
  137. typedef enum {
  138.       I_EMPTY,
  139.       I_ERROR,
  140.       I_RESTART,
  141.       I_CALLEE,
  142.       I_CALLER,
  143.       I_GRPACK,
  144.       I_INITA,
  145.       I_INITA_SEND,
  146.       I_INITB,
  147.       I_INITB_SEND,
  148.       I_INITC,
  149.       I_INITC_SEND,
  150.       I_COMPLETE
  151.       } I_STATE;
  152.  
  153. #define between(a,b,c) ((a<=b && b<c) || \
  154.                         (c<a && a<=b) || \
  155.                         (b<c && c<a))
  156.  
  157. #define nextpkt(x)    ((x + 1) % MAXSEQ)
  158. #define nextbuf(x)    ((x + 1) % (nwindows+1))
  159.  
  160. /*--------------------------------------------------------------------*/
  161. /*              Global variables for packet definitions               */
  162. /*--------------------------------------------------------------------*/
  163.  
  164. currentfile();
  165.  
  166. static int rwl, swl, swu, rwu, irec, lazynak;
  167. static unsigned nbuffers;
  168. static int rbl, sbl, sbu;
  169. static INTEGER nerr;
  170. static unsigned outlen[NBUF], inlen[NBUF], xmitlen[NBUF];
  171. static boolean arrived[NBUF];
  172. static size_t nwindows;
  173. static char *outbuf[NBUF];
  174. static char *inbuf[NBUF];
  175. static time_t ftimer[NBUF];
  176. static int timeouts, outsequence, naksin, naksout, screwups;
  177. static int reinit, shifts, badhdr, resends;
  178. static unsigned char *grpkt = NULL;
  179. static boolean variablepacket;  /* "v" or in modem file              */
  180.  
  181. /*--------------------------------------------------------------------*/
  182. /*                    Internal function prototypes                    */
  183. /*--------------------------------------------------------------------*/
  184.  
  185. static int initialize(const boolean caller, const char protocol );
  186.  
  187. static int  gmachine(const int timeout);
  188.  
  189. static void gspack(int  type,
  190.                    int  yyy,
  191.                    int  xxx,
  192.                    int  len,
  193.                    unsigned xmit,
  194.                    char  *data);
  195.  
  196. static int  grpack(int  *yyy,
  197.                    int  *xxx,
  198.                    int  *len,
  199.                    char *data,
  200.                    const int timeout);
  201.  
  202. static void gstats( void );
  203.  
  204. static unsigned int checksum(char *data, int len);
  205.  
  206. /****************** SUB SUB SUB PACKET HANDLER ************/
  207.  
  208. /*--------------------------------------------------------------------*/
  209. /*    g o p e n p k                                                   */
  210. /*                                                                    */
  211. /*    Initialize processing for protocol                              */
  212. /*--------------------------------------------------------------------*/
  213.  
  214. int Gopenpk(const boolean caller)
  215. {
  216.    return initialize(caller , 'G');
  217. } /* Gopenpk */
  218.  
  219. /*--------------------------------------------------------------------*/
  220. /*    v o p e n p k                                                   */
  221. /*                                                                    */
  222. /*    Initialize processing for protocol                              */
  223. /*--------------------------------------------------------------------*/
  224.  
  225. int vopenpk(const boolean caller)
  226. {
  227.    return initialize(caller, 'v');
  228. } /* vopenpk */
  229.  
  230. /*--------------------------------------------------------------------*/
  231. /*    g o p e n p k                                                   */
  232. /*                                                                    */
  233. /*    Initialize processing for protocol                              */
  234. /*--------------------------------------------------------------------*/
  235.  
  236. int gopenpk(const boolean caller)
  237. {
  238.    return initialize(caller, 'g');
  239. } /* vopenpk */
  240.  
  241. /*--------------------------------------------------------------------*/
  242. /*    i n i t i a l i z e                                             */
  243. /*                                                                    */
  244. /*    Initialize processing for protocol                              */
  245. /*--------------------------------------------------------------------*/
  246.  
  247. static int initialize(const boolean caller, const char protocol )
  248. {
  249.    int i, xxx, yyy, len, maxwindows;
  250.  
  251. #define B_SENT_INITA 0x01
  252. #define B_SENT_INITB 0x02
  253. #define B_SENT_INITC 0x04
  254. #define B_RECV_INITA 0x10
  255. #define B_RECV_INITB 0x20
  256. #define B_RECV_INITC 0x40
  257. #define B_INITA (B_SENT_INITA | B_RECV_INITA)
  258. #define B_INITB (B_SENT_INITB | B_RECV_INITB)
  259. #define B_INITC (B_SENT_INITC | B_RECV_INITC)
  260.  
  261.    int  flags = 0x00;   /* Init state flags, as defined above  */
  262.  
  263.    I_STATE state;
  264.  
  265. /*--------------------------------------------------------------------*/
  266. /* Read modem file values for the number of windows and packet sizes  */
  267. /*--------------------------------------------------------------------*/
  268.  
  269.    pktsize = GetGPacket( MAXPACK, protocol );
  270.    maxwindows = GetGWindow(
  271.                      min( MAXWINDOW, RECV_BUF / (pktsize+HDRSIZE)),
  272.                      protocol);
  273.  
  274.    variablepacket = bmodemflag[MODEM_VARIABLEPACKET] | (protocol == 'v');
  275.  
  276.    grpkt = malloc( pktsize + HDRSIZE );
  277.  
  278. /*--------------------------------------------------------------------*/
  279. /*                     Initialize error counters                      */
  280. /*--------------------------------------------------------------------*/
  281.  
  282.    timeouts = outsequence = naksin = naksout = screwups =
  283.       shifts = badhdr = resends = reinit = 0;
  284.  
  285. /*--------------------------------------------------------------------*/
  286. /*                    Initialize proto parameters                     */
  287. /*--------------------------------------------------------------------*/
  288.  
  289.    nerr = nbuffers = 0;
  290.    sbl = swl = swu = sbu = 1;
  291.    rbl = rwl = 0;
  292.    nwindows = maxwindows;
  293.    rwu = nwindows - 1;
  294.  
  295.    for (i = 0; i < NBUF; i++)
  296.    {
  297.       ftimer[i] = 0;
  298.       arrived[i] = FALSE;
  299.    }
  300.  
  301. /*--------------------------------------------------------------------*/
  302. /*                          3-way handshake                           */
  303. /*--------------------------------------------------------------------*/
  304.  
  305. /*--------------------------------------------------------------------*/
  306. /*    The three-way handshake should be independent of who            */
  307. /*    initializes it, but it seems that some versions of uucico       */
  308. /*    assume that the caller sends first and the callee responds.     */
  309. /*    This only matters if we are the callee and the first packet     */
  310. /*    is garbled.  If we send a packet, the other side will assume    */
  311. /*    that we must have seen the packet they sent and will never      */
  312. /*    time out and send it again.  Therefore, if we are the callee    */
  313. /*    we don't send a packet the first time through the loop.         */
  314. /*    This can still fail, but should usually work, and, after        */
  315. /*    all, if the initialization packets are received correctly       */
  316. /*    there will be no problem no matter what we do.                  */
  317. /*                                                                    */
  318. /*    (The above quoted verbatim from Ian Taylor)                     */
  319. /*--------------------------------------------------------------------*/
  320.  
  321.    state = caller ? I_CALLER : I_CALLEE;
  322.  
  323. /*--------------------------------------------------------------------*/
  324. /*    Exchange initialization messages with the other system.         */
  325. /*                                                                    */
  326. /*    A problem:                                                      */
  327. /*                                                                    */
  328. /*    We send INITA; it gets received                                 */
  329. /*    We receive INITA                                                */
  330. /*    We send INITB; it gets garbled                                  */
  331. /*    We receive INITB                                                */
  332. /*                                                                    */
  333. /*    We have seen and sent INITB, so we start to send INITC.  The    */
  334. /*    other side as sent INITB but not seen it, so it times out       */
  335. /*    and resends INITB.  We will continue sending INITC and the      */
  336. /*    other side will continue sending INITB until both sides give    */
  337. /*    up and start again with INITA.                                  */
  338. /*                                                                    */
  339. /*    It might seem as though if we are sending INITC and receive     */
  340. /*    INITB, we should resend our INITB, but this could cause         */
  341. /*    infinite echoing of INITB on a long-latency line.  Rather       */
  342. /*    than risk that, I have implemented a fast drop-back             */
  343. /*    procedure.  If we are sending INITB and receive INITC, the      */
  344. /*    other side has gotten ahead of us.  We immediately fail and     */
  345. /*    begin again with INITA.  For the other side, if we are          */
  346. /*    sending INITC and see INITA, we also immediately fail back      */
  347. /*    to INITA.                                                       */
  348. /*                                                                    */
  349. /*    Unfortunately, this doesn't work for the other case, in         */
  350. /*    which we are sending INITB but the other side has not yet       */
  351. /*    seen INITA.  As far as I can see, if this happens we just       */
  352. /*    have to wait until we time out and resend INITA.                */
  353. /*                                                                    */
  354. /*    (The above also quoted verbatim from Ian Taylor; however, the   */
  355. /*    code and associated bugs are all Drew's)                        */
  356. /*--------------------------------------------------------------------*/
  357.  
  358. /*--------------------------------------------------------------------*/
  359. /*    A note about the games with the variable "flags", which is      */
  360. /*    bit twiddled alot below.  The statement below:                  */
  361. /*                                                                    */
  362. /*          flags = (flags & B_SENT_INITA) | B_RECV_INITA;            */
  363. /*                                                                    */
  364. /*    works to turn off all the bits in flags except B_SENT_INITA     */
  365. /*    if it was already on, and then turns on flag B_RECV_INITA.      */
  366. /*    We use statements like this to reset most of the flags at       */
  367. /*    once, leaving one or two bits on; this in turn allows us to     */
  368. /*    check in later states that the previous two states were the     */
  369. /*    expected ones.                                                  */
  370. /*                                                                    */
  371. /*    Likewise, the following statement:                              */
  372. /*                                                                    */
  373. /*          state = (flags & B_SENT_INITA) ?                          */
  374. /*                         I_INITB_SEND : I_INITA_SEND;               */
  375. /*                                                                    */
  376. /*    tests to see if B_SENT_INITA was already set, and return the    */
  377. /*    "true" condition (I_INITB_SEND) otherwise return the "false"    */
  378. /*    (I_INITA_SEND).                                                 */
  379. /*--------------------------------------------------------------------*/
  380.  
  381.  
  382.    while( state != I_COMPLETE )
  383.    {
  384.       printmsg(4, "gopenpk: I State = %2d, flag = 0x%02x",
  385.                (int) state, (int) flags);
  386.  
  387.       switch( state )
  388.       {
  389.  
  390. /*--------------------------------------------------------------------*/
  391. /*                          Receive a packet                          */
  392. /*--------------------------------------------------------------------*/
  393.  
  394.          case I_GRPACK:
  395.             switch (grpack(&yyy, &xxx, &len, NULL, M_gPacketTimeout ))
  396.             {
  397.  
  398.                case INITA:
  399.                   printmsg(5, "**got INITA");
  400.                   state = I_INITA;
  401.                   break;
  402.  
  403.                case INITB:
  404.                   printmsg(5, "**got INITB");
  405.                   state = I_INITB;
  406.                   break;
  407.  
  408.                case INITC:
  409.                   printmsg(5, "**got INITC");
  410.                   state = I_INITC;
  411.                   break;
  412.  
  413.                case EMPTY:
  414.                   printmsg(GDEBUG, "**got EMPTY");
  415.                   state = I_EMPTY;
  416.  
  417.                   if (bmodemflag[MODEM_CD] && !CD())
  418.                   {
  419.                      printmsg(0,"gopenpk: Modem carrier lost");
  420.                      return FAILED;
  421.                   }
  422.                   break;
  423.  
  424.                case CLOSE:
  425.                   printmsg(GDEBUG, "**got CLOSE");
  426.                   gspack(CLOSE, 0, 0, 0, 0, NULL);
  427.                   return FAILED;
  428.  
  429.                default:
  430.                   printmsg(GDEBUG, "**got SCREW UP");
  431.                   state = I_ERROR;
  432.                   break;
  433.             }
  434.  
  435.             if (bmodemflag[MODEM_CD] && !CD())
  436.             {
  437.                printmsg(0,"gopenpk: Modem carrier lost");
  438.                return FAILED;
  439.             }
  440.             break;
  441.  
  442. /*--------------------------------------------------------------------*/
  443. /*                         Initialize states                          */
  444. /*--------------------------------------------------------------------*/
  445.  
  446.          case I_CALLER:
  447.             state = I_INITA_SEND;
  448.             break;
  449.  
  450.          case I_CALLEE:
  451.             state = I_GRPACK;
  452.             break;
  453.  
  454. /*--------------------------------------------------------------------*/
  455. /*                  Process received or sent packets                  */
  456. /*--------------------------------------------------------------------*/
  457.  
  458.          case I_INITA:
  459.             if (yyy < (int) nwindows)
  460.             {
  461.                nwindows = yyy;
  462.                rwu = nwindows - 1;
  463.             }
  464.             flags = (flags & B_SENT_INITA) | B_RECV_INITA;
  465.             state = (flags & B_SENT_INITA) ? I_INITB_SEND : I_INITA_SEND;
  466.             break;
  467.  
  468.          case I_INITA_SEND:
  469.             gspack(INITA, 0, 0, 0, pktsize, NULL);
  470.             flags = (flags & B_RECV_INITA) | B_SENT_INITA;
  471.             state = I_GRPACK;
  472.             break;
  473.  
  474.          case I_INITB:
  475.             if ((flags & (B_RECV_INITA | B_SENT_INITA)) ==
  476.                          (B_RECV_INITA | B_SENT_INITA))
  477.             {
  478.                i = (int) 8 * (2 << (yyy+1));
  479.                if (i < (int) pktsize)
  480.                   pktsize = i;
  481.                flags = (flags & B_SENT_INITB) | B_RECV_INITB;
  482.                state = (flags & B_SENT_INITB) ? I_INITC_SEND : I_INITB_SEND;
  483.             } /* if */
  484.             else
  485.                state = I_RESTART;
  486.             break;
  487.  
  488.          case I_INITB_SEND:
  489.             gspack(INITB, 0, 0, 0, pktsize, NULL);
  490.                                        /* Data segment (packet) size    */
  491.             flags = (flags & (B_INITA | B_RECV_INITB)) | B_SENT_INITB;
  492.             state = I_GRPACK;
  493.             break;
  494.  
  495.          case I_INITC:
  496.             if ((flags & (B_RECV_INITB | B_SENT_INITB)) ==
  497.                            (B_RECV_INITB | B_SENT_INITB))
  498.             {
  499.                if (yyy < (int) nwindows)
  500.                {
  501.                   nwindows = yyy;
  502.                   rwu = nwindows - 1;
  503.                }
  504.                flags = (flags & B_SENT_INITC) | B_RECV_INITC;
  505.                state = (flags & B_SENT_INITC) ? I_COMPLETE : I_INITC_SEND;
  506.             }
  507.             else
  508.                state = I_RESTART;
  509.             break;
  510.  
  511.          case I_INITC_SEND:
  512.             gspack(INITC, 0, 0, 0, pktsize, NULL);
  513.             flags = (flags & (B_INITB | B_RECV_INITC)) | B_SENT_INITC;
  514.             state = (flags & B_RECV_INITC) ? I_COMPLETE : I_GRPACK;
  515.             break;
  516.  
  517. /*--------------------------------------------------------------------*/
  518. /*                            Error states                            */
  519. /*--------------------------------------------------------------------*/
  520.  
  521.          case I_EMPTY:
  522.             timeouts++;
  523.             state = I_RESTART;
  524.             break;
  525.  
  526.          case I_ERROR:
  527.             screwups++;
  528.             state = I_RESTART;
  529.             break;
  530.  
  531.          case I_RESTART:
  532.             printmsg(2,"gopenpk: Restarting initialize sequence");
  533.             nerr++;
  534.             flags = 0x00;
  535.             state = I_INITA_SEND;
  536.             break;
  537.  
  538.       } /* switch */
  539.  
  540.       if ( terminate_processing )
  541.       {
  542.          printmsg(0,"gopenpk: Terminated by user");
  543.          return FAILED;
  544.       }
  545.  
  546.       if (nerr >= M_MaxErr)
  547.       {
  548.          remote_stats.errors += nerr;
  549.          nerr = 0;
  550.          printmsg(0,
  551.             "gopenpk: Consecutive error limit of %ld exceeded, "
  552.                      "%ld total errors",
  553.              (long) M_MaxErr, remote_stats.errors);
  554.          return(FAILED);
  555.       }
  556.    } /* while */
  557.  
  558. /*--------------------------------------------------------------------*/
  559. /*                    Allocate the needed buffers                     */
  560. /*--------------------------------------------------------------------*/
  561.  
  562.    grpkt = realloc( grpkt, pktsize + HDRSIZE );
  563.  
  564.    i = 0;
  565.    while( i <= (int) nwindows)
  566.    {
  567.  
  568.       inbuf[i] = malloc( pktsize );
  569.       if (inbuf[i] == (char *) NULL ) checkref( NULL );
  570.                               /* Forces the regular error message */
  571.  
  572.       outbuf[i] = malloc( pktsize );
  573.       checkref( outbuf[i] );
  574.  
  575.       i ++;
  576.  
  577.    } /* while */
  578.  
  579.    nerr = 0;
  580.    lazynak = 0;
  581.  
  582. #ifdef WIN32
  583.    printmsg(2,"Short packets %sabled, "
  584.               "Window size %d, "
  585.               "Packet size %d\n",
  586.             variablepacket ? "en" : "dis", nwindows, pktsize );
  587. #else
  588.    printmsg(2,"Smart packets %sabled, "
  589.               "Window size %d, "
  590.               "Packet size %d, "
  591.               "Memory avail %u",
  592.             variablepacket ? "en" : "dis", nwindows, pktsize,
  593.             memavail());
  594. #endif
  595.  
  596.    return(OK); /* channel open */
  597.  
  598. } /*initialize*/
  599.  
  600. /*--------------------------------------------------------------------*/
  601. /*    g f i l e p k t                                                 */
  602. /*                                                                    */
  603. /*    Begin a file transfer (not used by "g" protocol)                */
  604. /*--------------------------------------------------------------------*/
  605.  
  606. int gfilepkt( void )
  607. {
  608.  
  609.    return OK;
  610.  
  611. } /* gfilepkt */
  612.  
  613. /*--------------------------------------------------------------------*/
  614. /*    g c l o s e p k                                                 */
  615. /*                                                                    */
  616. /*    Close packet machine                                            */
  617. /*--------------------------------------------------------------------*/
  618.  
  619. int gclosepk()
  620. {
  621.    unsigned i;
  622.  
  623.    for (i = 0; i < MAXTRY; i++)
  624.    {
  625.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  626.       if (gmachine(M_gPacketTimeout) == CLOSE)
  627.          break;
  628.    } /* for (i = 0; i < MAXTRY; i++) */
  629.  
  630. /*--------------------------------------------------------------------*/
  631. /*                        Release our buffers                         */
  632. /*--------------------------------------------------------------------*/
  633.  
  634.    i = 0;
  635.  
  636.    while( i <= nwindows )
  637.    {
  638.       free( (void *)inbuf[i] );
  639.       free( outbuf[i] );
  640.       inbuf[i] = outbuf[i] = NULL;
  641.       i++;
  642.    } /* while( i < NBUF ) */
  643.  
  644.    free( grpkt );
  645.    grpkt = NULL;
  646.  
  647. /*--------------------------------------------------------------------*/
  648. /*                Report the results of our adventures                */
  649. /*--------------------------------------------------------------------*/
  650.  
  651.    gstats();
  652.  
  653. /*--------------------------------------------------------------------*/
  654. /*                          Return to caller                          */
  655. /*--------------------------------------------------------------------*/
  656.  
  657.    return(0);
  658.  
  659. } /*gclosepk*/
  660.  
  661. /*--------------------------------------------------------------------*/
  662. /*    g s t a t s                                                     */
  663. /*                                                                    */
  664. /*    Report summary of errors for processing                         */
  665. /*--------------------------------------------------------------------*/
  666.  
  667. static void gstats( void )
  668. {
  669.    remote_stats.errors += nerr;
  670.    nerr = 0;
  671.    if ( remote_stats.errors || badhdr )
  672.    {
  673.       printmsg(0,
  674.          "%d time outs, %d port reinits, %d out of seq pkts, "
  675.          "%d NAKs rec, %d NAKs sent",
  676.             timeouts, reinit, outsequence, naksin, naksout);
  677.       printmsg(0,
  678.          "%d invalid pkt types, %d re-syncs, %d bad pkt hdrs, %d pkts resent",
  679.             screwups, shifts, badhdr, resends);
  680.    } /* if ( remote_stats.errors || shifts || badhdr ) */
  681. } /* gstats */
  682.  
  683. /*--------------------------------------------------------------------*/
  684. /*    g g e t p k t                                                   */
  685. /*                                                                    */
  686. /*    Gets no more than a packet's worth of data from                 */
  687. /*    the "packet I/O state machine".  May have to                    */
  688. /*    periodically run the packet machine to get some packets.        */
  689. /*                                                                    */
  690. /*    on input:   don't care                                          */
  691. /*    on return:  data+\0 and length in len.                          */
  692. /*                                                                    */
  693. /*    ret(0)   if all's well                                          */
  694. /*    ret(-1) if problems (failed)                                    */
  695. /*--------------------------------------------------------------------*/
  696.  
  697. int ggetpkt(char *data, int *len)
  698. {
  699.    int   retry = M_MaxErr;
  700.    time_t start;
  701. #ifdef _DEBUG
  702.    int savedebug = debuglevel;
  703. #endif
  704.  
  705.    irec = 1;
  706.    checkref( data );
  707.  
  708. /*--------------------------------------------------------------------*/
  709. /*                Loop to wait for the desired packet                 */
  710. /*--------------------------------------------------------------------*/
  711.  
  712.    time( &start );
  713.    while (!arrived[rbl] && retry)
  714.    {
  715.       if (gmachine(M_gPacketTimeout) != POK)
  716.          return(-1);
  717.  
  718.       if (!arrived[rbl] )
  719.       {
  720.          time_t now;
  721.          if (time( &now ) > (start + M_gPacketTimeout) )
  722.          {
  723. #ifdef _DEBUG
  724.             if ( debuglevel < 6 )
  725.                debuglevel = 6;
  726. #endif
  727.             printmsg(GDEBUG,
  728.                      "ggetpkt: Timeout %d waiting for inbound packet %d",
  729.                      M_MaxErr - --retry, remote_stats.packets + 1);
  730.             timeouts++;
  731.             start = now;
  732.          } /* if (time( now ) > (start + M_gPacketTimeout) ) */
  733.       } /* if (!arrived[rbl] ) */
  734.    } /* while (!arrived[rbl] && i) */
  735.  
  736. #ifdef _DEBUG
  737.    debuglevel = savedebug;
  738. #endif
  739.  
  740.    if (!arrived[rbl])
  741.    {
  742.       printmsg(0,"ggetpkt: Remote host failed to respond after %ld seconds",
  743.                (long) M_gPacketTimeout * M_MaxErr);
  744.       gclosepk();
  745.       return -1;
  746.    }
  747.  
  748. /*--------------------------------------------------------------------*/
  749. /*                           Got a packet!                            */
  750. /*--------------------------------------------------------------------*/
  751.  
  752.    *len = inlen[rbl];
  753.    memcpy(data, inbuf[rbl], *len);
  754.  
  755.    arrived[rbl] = FALSE;      /* Buffer is now emptied               */
  756.    rwu = nextpkt(rwu);        /* bump receive window                 */
  757.  
  758.    return(0);
  759.  
  760. } /*ggetpkt*/
  761.  
  762.  
  763. /*
  764.    g s e n d p k t
  765.  
  766.    Put at most a packet's worth of data in the packet state
  767.    machine for transmission.
  768.    May have to run the packet machine a few times to get
  769.    an available output slot.
  770.  
  771.    on input: data=*data; len=length of data in data.
  772.  
  773.    return:
  774.     0 if all's well
  775.    -1 if problems (failed)
  776. */
  777.  
  778. int gsendpkt(char *data, int len)
  779. {
  780.    int delta;
  781. #ifdef _DEBUG
  782.    int savedebug = debuglevel;
  783. #endif
  784.  
  785.    checkref( data );
  786.    irec = 0;
  787.    /* WAIT FOR INPUT i.e. if weve sent SWINDOW pkts and none have been
  788.       acked, wait for acks */
  789.    while (nbuffers >= nwindows)
  790.       if (gmachine(0) != POK)    /* Spin with no timeout             */
  791.          return(-1);
  792.  
  793. /*--------------------------------------------------------------------*/
  794. /*               Place packet in table and mark unacked               */
  795. /*--------------------------------------------------------------------*/
  796.  
  797.    memcpy(outbuf[sbu], data, len);
  798.  
  799. /*--------------------------------------------------------------------*/
  800. /*                       Handle short packets.                        */
  801. /*--------------------------------------------------------------------*/
  802.  
  803.    xmitlen[sbu] = pktsize;
  804.    if (variablepacket)
  805.       while ( ((len * 2) < (int) xmitlen[sbu]) && (xmitlen[sbu] > MINPKT) )
  806.          xmitlen[sbu] /= 2;
  807.  
  808.    if ( xmitlen[sbu] < MINPKT )
  809.    {
  810.       printmsg(0,"gsendpkt: Bad packet size %d, "
  811.                "data length %d",
  812.                xmitlen[sbu], len);
  813.       xmitlen[sbu] = MINPKT;
  814.    }
  815.  
  816.    delta = xmitlen[sbu] - len;
  817.    if (delta > 127)
  818.    {
  819.       memmove(outbuf[sbu] + 2, outbuf[sbu], len);
  820.       memset(outbuf[sbu]+len+2, 0, delta - 2);
  821.                               /* Pad with nulls.  Ugh.               */
  822.       outbuf[sbu][0] = (unsigned char) ((delta & 0x7f) | 0x80);
  823.       outbuf[sbu][1] = (unsigned char) (delta >> 7);
  824.    } /* if (delta > 127) */
  825.    else if (delta > 0 )
  826.    {
  827.       memmove(outbuf[sbu] + 1, outbuf[sbu], len);
  828.       outbuf[sbu][0] = (unsigned char) delta;
  829.       memset(outbuf[sbu]+len+1, 0, delta - 1);
  830.                               /* Pad with nulls.  Ugh.               */
  831.    } /* else if (delta > 0 )  */
  832.  
  833. /*--------------------------------------------------------------------*/
  834. /*                            Mark packet                             */
  835. /*--------------------------------------------------------------------*/
  836.  
  837.    outlen[sbu] = len;
  838.    ftimer[sbu] = time(nil(long));
  839.    nbuffers++;
  840.  
  841. /*--------------------------------------------------------------------*/
  842. /*                              send it                               */
  843. /*--------------------------------------------------------------------*/
  844.  
  845.    gspack(DATA, rwl, swu, outlen[sbu], xmitlen[sbu], outbuf[sbu]);
  846.  
  847.    swu = nextpkt(swu);        /* Bump send window                    */
  848.    sbu = nextbuf( sbu );      /* Bump to next send buffer            */
  849.  
  850. #ifdef _DEBUG
  851.    debuglevel = savedebug;
  852. #endif
  853.  
  854.    return(0);
  855.  
  856. } /*gsendpkt*/
  857.  
  858.  
  859. /*--------------------------------------------------------------------*/
  860. /*    g e o f p k t                                                   */
  861. /*                                                                    */
  862. /*    Transmit EOF to the other system                                */
  863. /*--------------------------------------------------------------------*/
  864.  
  865. int geofpkt( void )
  866. {
  867.    if (gsendpkt("", 0))          /* Empty packet == EOF              */
  868.       return FAILED;
  869.    else
  870.       return OK;
  871. } /* geofpkt */
  872.  
  873. /*--------------------------------------------------------------------*/
  874. /*    g w r m s g                                                     */
  875. /*                                                                    */
  876. /*    Send a message to remote system                                 */
  877. /*--------------------------------------------------------------------*/
  878.  
  879. int gwrmsg( char *s )
  880. {
  881.    for(; strlen(s) >= pktsize; s += pktsize) {
  882.       int result = gsendpkt(s, pktsize);
  883.       if (result)
  884.          return result;
  885.    }
  886.  
  887.    return gsendpkt(s, strlen(s)+1);
  888. } /* gwrmsg */
  889.  
  890. /*--------------------------------------------------------------------*/
  891. /*    g r d m s g                                                     */
  892. /*                                                                    */
  893. /*    Read a message from the remote system                           */
  894. /*--------------------------------------------------------------------*/
  895.  
  896. int grdmsg( char *s)
  897. {
  898.    for ( ;; )
  899.    {
  900.       int len;
  901.       int result = ggetpkt( s, &len );
  902.       if (result || (s[len-1] == '\0'))
  903.          return result;
  904.       s += len;
  905.    } /* for */
  906.  
  907. } /* grdmsg */
  908.  
  909. /**********  Packet Machine  ********** RH Lamb 3/87 */
  910.  
  911. /*--------------------------------------------------------------------*/
  912. /*    g m a c h i n e                                                 */
  913. /*                                                                    */
  914. /*    Ideally we would like to fork this process off in an            */
  915. /*    infinite loop and send and receive packets through "inbuf"      */
  916. /*    and "outbuf".  Can't do this in MS-DOS so we setup "getpkt"     */
  917. /*    and "sendpkt" to call this routine often and return only        */
  918. /*    when the input buffer is empty thus "blocking" the packet-      */
  919. /*    machine task.                                                   */
  920. /*--------------------------------------------------------------------*/
  921.  
  922. static int gmachine(const int timeout )
  923. {
  924.    static time_t idletimer = 0;
  925.  
  926.    boolean done   = FALSE;    /* True = drop out of machine loop  */
  927.    boolean close  = FALSE;    /* True = terminate connection upon
  928.                                         exit                      */
  929.    boolean inseq  = TRUE;     /* True = Count next out of sequence
  930.                                         packet as an error           */
  931.    while ( !done )
  932.    {
  933.       boolean resend = FALSE;    /* True = resend data packets       */
  934.       boolean donak  = FALSE;    /* True = NAK the other system      */
  935.       unsigned long packet_no = remote_stats.packets;
  936.  
  937.       int pkttype, rack, rseq, rlen, rbuf, i1;
  938.       time_t now;
  939.  
  940. #ifdef UDEBUG
  941.       if ( debuglevel >= 7 )     /* Optimize processing a little bit */
  942.       {
  943.  
  944.          printmsg(10, "* send %d %d < W < %d %d, "
  945.                       "receive %d %d < W < %d, "
  946.                       "error %d, packet %d",
  947.             swl, sbl, swu, sbu, rwl, rbl, rwu, nerr,
  948.             (long) remote_stats.packets);
  949.  
  950. /*--------------------------------------------------------------------*/
  951. /*    Waiting for ACKs for swl to swu-1.  Next pkt to send=swu        */
  952. /*    rwl=expected pkt                                                */
  953. /*--------------------------------------------------------------------*/
  954.  
  955.       }
  956. #endif
  957.  
  958. /*--------------------------------------------------------------------*/
  959. /*             Attempt to retrieve a packet and handle it             */
  960. /*--------------------------------------------------------------------*/
  961.  
  962.       pkttype = grpack(&rack, &rseq, &rlen, inbuf[nextbuf(rbl)], timeout);
  963.       time(&now);
  964.       switch (pkttype) {
  965.  
  966.          case CLOSE:
  967.             remote_stats.packets++;
  968.             printmsg(GDEBUG, "**got CLOSE");
  969.             close = done = TRUE;
  970.             break;
  971.  
  972.          case EMPTY:
  973.             printmsg(timeout ? GDEBUG : 8, "**got EMPTY");
  974.  
  975.             if (bmodemflag[MODEM_CD] && !CD())
  976.             {
  977.                printmsg(0,"gmachine: Modem carrier lost");
  978.                nerr++;
  979.                close = TRUE;
  980.             }
  981.  
  982.             if ( terminate_processing )
  983.             {
  984.                printmsg(0,"gmachine: User aborted processing");
  985.                close = TRUE;
  986.             }
  987.  
  988.             if (ftimer[sbl])
  989.             {
  990. #ifdef UDEBUG
  991.                printmsg(6, "---> seq, elapst %d %ld", sbl,
  992.                     ftimer[sbl] - now);
  993. #endif
  994.                if ( ftimer[sbl] <= (now - M_gPacketTimeout))
  995.                {
  996.                    printmsg(4, "*** timeout %d (%ld)",
  997.                                sbl, (long) remote_stats.packets);
  998.                        /* Since "g" is "go-back-N", when we time out we
  999.                           must send the last N pkts in order.  The generalized
  1000.                           sliding window scheme relaxes this reqirment. */
  1001.                    nerr++;
  1002.                    timeouts++;
  1003.                    resend = TRUE;
  1004.                } /* if */
  1005.             } /* if */
  1006.  
  1007.             done = TRUE;
  1008.             break;
  1009.  
  1010.          case DATA:
  1011.             printmsg(5, "**got DATA %d %d", rack, rseq);
  1012.             i1 = nextpkt(rwl);   /* (R+1)%8 <-- -->(R+W)%8 */
  1013.             if (i1 == rseq) {
  1014.                lazynak--;
  1015.                remote_stats.packets++;
  1016.                idletimer = now;
  1017.                rwl = i1;
  1018.                rbl = nextbuf( rbl );
  1019.                inseq = arrived[rbl] = TRUE;
  1020.                inlen[rbl] = rlen;
  1021.                printmsg(5, "*** ACK d %d %d", rwl, rbl);
  1022.                gspack(ACK, rwl, 0, 0, 0, NULL);
  1023.                done = TRUE;   /* return to caller when finished      */
  1024.                               /* in a mtask system, unneccesary      */
  1025.             } else {
  1026.                if (inseq || ( now > (idletimer + M_gPacketTimeout)))
  1027.                {
  1028.                   donak = TRUE;  /* Only flag first out of sequence
  1029.                                     packet as error, since we know
  1030.                                     following ones also bad             */
  1031.                   outsequence++;
  1032.                   inseq = FALSE;
  1033.                }
  1034.                printmsg(GDEBUG, "*** unexpect %d ne %d (%d - %d)",
  1035.                                        rseq, i1, rwl, rwu);
  1036.             } /* else */
  1037.  
  1038.             if ( swl == swu )       /* We waiting for an ACK?     */
  1039.                break;               /* No --> Skip ACK processing */
  1040.             /* else Fall through to ACK case */
  1041.  
  1042.          case NAK:
  1043.          case ACK:
  1044.             if (pkttype == NAK)
  1045.             {
  1046.                nerr++;
  1047.                naksin++;
  1048.                printmsg(5, "**got NAK %d", rack);
  1049.                resend = TRUE;
  1050.             }
  1051.             else if (pkttype == ACK)
  1052.                printmsg(5, "**got ACK %d", rack);
  1053.  
  1054.             while(between(swl, rack, swu))
  1055.             {                             /* S<-- -->(S+W-1)%8 */
  1056.                remote_stats.packets++;
  1057.                printmsg(5, "*** ACK %d", swl);
  1058.                ftimer[sbl] = 0;
  1059.                idletimer = now;
  1060.                nbuffers--;
  1061.                done = TRUE;            /* Get more data for input */
  1062.                swl = nextpkt(swl);
  1063.                sbl = nextbuf(sbl);
  1064.             } /* while */
  1065.  
  1066.             if (!done && (pkttype == ACK)) /* Find packet?         */
  1067.             {
  1068.                printmsg(GDEBUG,"*** ACK for bad packet %d (%d - %d)",
  1069.                            rack, swl, swu);
  1070.             } /* if */
  1071.             break;
  1072.  
  1073.          case ERROR:
  1074.             printmsg(GDEBUG, "*** got BAD CHK");
  1075.             naksout++;
  1076.             donak = TRUE;
  1077.             lazynak = 0;               /* Always NAK bad checksum */
  1078.             break;
  1079.  
  1080.          default:
  1081.             screwups++;
  1082.             nerr++;
  1083.             printmsg(GDEBUG, "*** got SCREW UP");
  1084.             break;
  1085.  
  1086.       } /* switch */
  1087.  
  1088. /*--------------------------------------------------------------------*/
  1089. /*      If we received an NAK or timed out, resend data packets       */
  1090. /*--------------------------------------------------------------------*/
  1091.  
  1092.       if ( resend )
  1093.       for (rack = swl,
  1094.            rbuf = sbl;
  1095.            between(swl, rack, swu);
  1096.            rack = nextpkt(rack), rbuf = nextbuf( rbuf ))
  1097.       {                          /* resend rack->(swu-1)             */
  1098.          resends++;
  1099.  
  1100.          if (( outbuf[rbuf] == NULL ))
  1101.          {
  1102.             printmsg(0,"gmachine: Transmit of NULL packet (%d %d)",
  1103.                      rwl, rbuf);
  1104.             panic();
  1105.          }
  1106.  
  1107.          if (( xmitlen[rbuf] == 0 ))
  1108.          {
  1109.             printmsg(0,"gmachine: Transmit of 0 length packet (%d %d)",
  1110.                      rwl, rbuf);
  1111.             panic();
  1112.          }
  1113.  
  1114.          gspack(DATA, rwl, rack, outlen[rbuf], xmitlen[rbuf], outbuf[rbuf]);
  1115.          printmsg(5, "*** resent %d", rack);
  1116.          idletimer = ftimer[rbuf] = now;
  1117.       } /* for */
  1118.  
  1119. /*--------------------------------------------------------------------*/
  1120. /*  If we have an error and have not recently sent a NAK, do so now.  */
  1121. /*  We then reset our counter so we receive at least a window full of */
  1122. /*                 packets before sending another NAK                 */
  1123. /*--------------------------------------------------------------------*/
  1124.  
  1125.       if ( donak )
  1126.       {
  1127.          nerr++;
  1128.          if ( (lazynak < 1) || (now > (idletimer + M_gPacketTimeout)))
  1129.          {
  1130.             printmsg(5, "*** NAK d %d", rwl);
  1131.             gspack(NAK, rwl, 0, 0, 0, NULL);
  1132.             naksout++;
  1133.             idletimer = now;
  1134.             lazynak = nwindows + 1;
  1135.          } /* if ( lazynak < 1 ) */
  1136.       } /* if ( donak ) */
  1137.  
  1138. /*--------------------------------------------------------------------*/
  1139. /*                   Update error counter if needed                   */
  1140. /*--------------------------------------------------------------------*/
  1141.  
  1142.       if ((close || (packet_no != remote_stats.packets)) && (nerr > 0))
  1143.       {
  1144.          printmsg(GDEBUG,"gmachine: Packet %ld had %ld errors during transfer",
  1145.                      remote_stats.packets, (long) nerr);
  1146.          remote_stats.errors += nerr;
  1147.          nerr = 0;
  1148.       }
  1149.  
  1150. /*--------------------------------------------------------------------*/
  1151. /*    If we have an excessive number of errors, drop out of the       */
  1152. /*    loop                                                            */
  1153. /*--------------------------------------------------------------------*/
  1154.  
  1155.       if (nerr >= M_MaxErr)
  1156.       {
  1157.          printmsg(0,
  1158.             "gmachine: Consecutive error limit of %d exceeded, %d total errors",
  1159.             M_MaxErr, nerr + remote_stats.errors);
  1160.          done = close = TRUE;
  1161.          gstats();
  1162.       }
  1163.    } /* while */
  1164.  
  1165. /*--------------------------------------------------------------------*/
  1166. /*    Return to caller, gracefully terminating packet machine if      */
  1167. /*    requested                                                       */
  1168. /*--------------------------------------------------------------------*/
  1169.  
  1170.    if ( close )
  1171.    {
  1172.       gspack(CLOSE, 0, 0, 0, 0, NULL);
  1173.       return CLOSE;
  1174.    }
  1175.    else
  1176.       return POK;
  1177.  
  1178. } /*gmachine*/
  1179.  
  1180.  
  1181. /*************** FRAMING *****************************/
  1182.  
  1183. /*
  1184.    g s p a c k
  1185.  
  1186.    Send a packet
  1187.  
  1188.    type=type yyy=pkrec xxx=timesent len=length<=pktsize data=*data
  1189.    ret(0) always
  1190. */
  1191.  
  1192. static void gspack(int type,
  1193.                    int yyy,
  1194.                    int xxx,
  1195.                    int len,
  1196.                    unsigned xmit,
  1197.                    char *data)
  1198. {
  1199.    unsigned int check, i;
  1200.    unsigned char header[HDRSIZE];
  1201.  
  1202. #ifdef   LINKTEST
  1203.    /***** Link Testing Mods *****/
  1204.    unsigned char  dpkerr[10];
  1205.    /***** End Link Testing Mods *****/
  1206. #endif   /* LINKTEST */
  1207.  
  1208. #ifdef   LINKTEST
  1209.    /***** Link Testing Mods - create artificial errors *****/
  1210.    printf("**n:normal,e:error,l:lost,p:partial,h:bad header,s:new seq--> ");
  1211.    gets(dpkerr);
  1212.    if (dpkerr[0] == 's')
  1213.       sscanf(&dpkerr[1], "%d", &xxx);
  1214.    /***** End Link Testing Mods *****/
  1215. #endif   /* LINKTEST */
  1216.  
  1217.    if ( debuglevel > 4 )
  1218.       printmsg(5, "send packet type %d, yyy=%d, xxx=%d, len=%d, buf = %d",
  1219.                type, yyy, xxx, len, xmit);
  1220.  
  1221.    header[0] = '\020';
  1222.    header[4] = (unsigned char) (type << 3);
  1223.  
  1224.    switch (type) {
  1225.  
  1226.       case CLOSE:
  1227.          break;   /* stop protocol */
  1228.  
  1229.       case NAK:
  1230.          header[4] += yyy;
  1231.          break;   /* reject */
  1232.  
  1233.       case SRJ:
  1234.          break;
  1235.  
  1236.       case ACK:
  1237.          header[4] += yyy;
  1238.          break;   /* ack */
  1239.  
  1240.       case INITA:
  1241.       case INITC:
  1242.          header[4] += nwindows;
  1243.          break;
  1244.  
  1245.       case INITB:
  1246.          i = MINPKT;
  1247.          while( i < xmit )
  1248.          {
  1249.             header[4] ++;
  1250.             i *= 2;
  1251.          }
  1252.          break;
  1253.  
  1254.       case DATA:
  1255.          header[4] = (unsigned char) (0x80 + (xxx << 3) + yyy);
  1256.          if (len < (int) xmit)      /* Short packet?              */
  1257.             header[4] |= 0x40;/* Count byte handled at higher level */
  1258.  
  1259. #ifdef UDEBUG
  1260.             printmsg(7, "data=|%.*s|", len, data);
  1261. #endif
  1262.          break;
  1263.  
  1264.       default:
  1265.          printmsg(0,"gspack: Invalid packet type %d",type);
  1266.          panic();
  1267.    } /* switch */
  1268.  
  1269. /*--------------------------------------------------------------------*/
  1270. /*    Now we finish up the header.  For data packets, determine       */
  1271. /*    the K number in header[1], which specifies the number of        */
  1272. /*    actual data bytes transmitted as a power of 2; we also          */
  1273. /*    compute a checksum on the data.                                 */
  1274. /*--------------------------------------------------------------------*/
  1275.  
  1276.    if (type == DATA)
  1277.    {
  1278.       header[1] = 1;
  1279.       i = MINPKT;
  1280.       while( i < xmit )
  1281.       {
  1282.          header[1] ++;
  1283.          i *= 2;
  1284.       }
  1285.  
  1286.       if ( i != xmit )        /* Did it come out exact power of 2?   */
  1287.       {
  1288.          printmsg(0,"Packet length error ... %d != %d for K = %d",
  1289.                i, xmit, (int) header[1]);
  1290.          panic();             /* No --> Well, we blew THAT math      */
  1291.       } /* if ( i != xmit ) */
  1292.  
  1293. /*--------------------------------------------------------------------*/
  1294. /*                        Compute the checksum                        */
  1295. /*--------------------------------------------------------------------*/
  1296.  
  1297.       check = checksum(data, xmit);
  1298.       i = header[4]; /* got to do this on PC for ex-or high bits */
  1299.       i &= 0xff;
  1300.       check = (check ^ i) & 0xffff;
  1301.       check = (0xaaaa - check) & 0xffff;
  1302.    }
  1303.    else {
  1304.       header[1] = 9;          /* Control packet size K number (9)    */
  1305.       check = (0xaaaa - header[4]) & 0xffff;
  1306.                               /* Simple checksum for control         */
  1307.    } /* else */
  1308.  
  1309.    header[2] = (unsigned char) (check & 0xff);
  1310.    header[3] = (unsigned char) ((check >> 8) & 0xff);
  1311.    header[5] = (unsigned char)
  1312.             ((header[1] ^ header[2] ^ header[3] ^ header[4]) & 0xff) ;
  1313.  
  1314. #ifdef   LINKTEST
  1315.    /***** More Link Testing Mods *****/
  1316.    switch(dpkerr[0]) {
  1317.    case 'e':
  1318.       data[10] = - data[10];
  1319.       break;
  1320.    case 'h':
  1321.       header[5] = - header[5];
  1322.       break;
  1323.    case 'l':
  1324.       return;
  1325.    case 'p':
  1326.       swrite((char *) header, HDRSIZE);
  1327.       if (header[1] != 9)
  1328.          swrite(data, xmit - 3);
  1329.       return;
  1330.    default:
  1331.       break;
  1332.    }
  1333.    /***** End Link Testing Mods *****/
  1334. #endif   /* LINKTEST */
  1335.  
  1336.    swrite((char *) header, HDRSIZE);      /* header is 6-bytes long */
  1337.    if (header[1] != 9)
  1338.       swrite(data, xmit);           /* data is always 64 bytes long */
  1339.  
  1340. } /*gspack*/
  1341.  
  1342.  
  1343. /*
  1344.    g r p a c k
  1345.  
  1346.    Read packet
  1347.  
  1348.    on return: yyy=pkrec xxx=pksent len=length<=PKTSIZE  data=*data
  1349.  
  1350.    ret(type)   ok
  1351.    ret(EMPTY)  input buf empty
  1352.    ret(ERROR)  bad header
  1353.  
  1354.    ret(EMPTY)  lost packet timeout
  1355.    ret(ERROR)  checksum error
  1356.    ret(-5)     packet size != 64
  1357.  
  1358.    NOTE (specifications for sread()):
  1359.  
  1360.    sread(buf, n, timeout)
  1361.       while(TRUE) {
  1362.          if (# of chars available >= n) (without dec internal counter)
  1363.             read n chars into buf (decrement internal char counter)
  1364.             break
  1365.     else
  1366.        if (time > timeout)
  1367.           break;
  1368.       }
  1369.       return(# of chars available)
  1370.  
  1371. */
  1372.  
  1373. static int grpack(int *yyy,
  1374.                   int *xxx,
  1375.                   int *len,
  1376.                   char *data,
  1377.                   const int timeout)
  1378. {
  1379.    static int got_hdr  = FALSE;
  1380.    static int received = 0;     /* Bytes already read into buffer */
  1381.    int needed;
  1382.  
  1383.    unsigned int type, check, checkchk, i, total = 0;
  1384.    unsigned char c, c2;
  1385.  
  1386.    time_t start;
  1387.  
  1388.    if (got_hdr)
  1389.       goto get_data;
  1390.  
  1391. /*--------------------------------------------------------------------*/
  1392. /*   Spin up to timeout waiting for a Control-P, our sync character   */
  1393. /*--------------------------------------------------------------------*/
  1394.  
  1395.    start = 0;
  1396.    while (!got_hdr)
  1397.    {
  1398.       unsigned char *psync;
  1399.  
  1400.       needed = HDRSIZE - received;
  1401.       if ( needed > 0 )       /* Have enough bytes for header?       */
  1402.       {                       /* No --> Read as much as we need      */
  1403.          int wait;
  1404.  
  1405.          if ( start == 0 )    /* First pass through data?            */
  1406.          {                    /* Yes --> Set timers up               */
  1407.             start = time(nil(time_t));
  1408.             wait = timeout;
  1409.          } /* if ( start == 0 ) */
  1410.          else {
  1411.             wait = (int) (time(NULL) - start) - timeout;
  1412.             if (wait < 0)     /* Negative timeout?                   */
  1413.                wait = 0;      /* Make it no time out                 */
  1414.          } /* else */
  1415.  
  1416.          if (sread((char *) &grpkt[received], needed, wait ) < (unsigned) needed )
  1417.                               /* Did we get the needed data?         */
  1418.             return EMPTY;     /* No --> Return to caller             */
  1419.  
  1420.          received += needed;
  1421.       } /* if ( needed < received ) */
  1422.  
  1423. /*--------------------------------------------------------------------*/
  1424. /*            Search for sync character in newly read data            */
  1425. /*--------------------------------------------------------------------*/
  1426.  
  1427. #ifdef UDEBUG
  1428.       printmsg(10,"grpack: Have %d characters after reading %d",
  1429.                received, needed);
  1430. #endif
  1431.  
  1432.       psync = memchr( grpkt, '\020', received );
  1433.       if ( psync == NULL )    /* Did we find the sync character?     */
  1434.          received = 0;        /* No --> Reset to empty buffer        */
  1435.       else if ( psync != grpkt ) /* First character in buffer?       */
  1436.       {                       /* No --> Make it first character      */
  1437.          received -= psync - grpkt;
  1438.          shifts++;
  1439.          memmove( grpkt, psync, received );
  1440.                               /* Shift buffer over                   */
  1441.       } /* else */
  1442.  
  1443. /*--------------------------------------------------------------------*/
  1444. /*    If we have read an entire packet header, then perform a         */
  1445. /*    simple XOR checksum to determine if it is valid.  If we have    */
  1446. /*    a valid checksum, drop out of this search, else drop the        */
  1447. /*    sync character and restart the scan.                            */
  1448. /*--------------------------------------------------------------------*/
  1449.  
  1450.       if ( received >= HDRSIZE )
  1451.       {
  1452.          i = (unsigned) (grpkt[1] ^ grpkt[2] ^ grpkt[3] ^
  1453.                         grpkt[4] ^ grpkt[5]);
  1454.          i &= 0xff;
  1455.          printmsg(i ? 2 : 10, "prpkt %02x %02x %02x %02x %02x .. %02x ",
  1456.             grpkt[1], grpkt[2], grpkt[3], grpkt[4], grpkt[5], i);
  1457.  
  1458.          if (i == 0)          /* Good header?                        */
  1459.             got_hdr = TRUE;   /* Yes --> Drop out of loop            */
  1460.          else {               /* No  --> Flag it, continue loop      */
  1461.             badhdr++;
  1462.             printmsg(GDEBUG, "*** bad pkt header ***");
  1463.             memmove( grpkt, &grpkt[ 1 ], --received );
  1464.                               /* Begin scanning for sync character
  1465.                                  with next byte                      */
  1466.          } /* else */
  1467.       } /* if ( received > HDRSIZE ) */
  1468.    } /* while */
  1469.  
  1470. /*--------------------------------------------------------------------*/
  1471. /*                       Handle control packets                       */
  1472. /*--------------------------------------------------------------------*/
  1473.  
  1474.    if (grpkt[1] == 9)
  1475.    {
  1476.       if ( data != NULL )
  1477.          *data = '\0';
  1478.       *len = 0;
  1479.       c = grpkt[4];
  1480.       type = c >> 3;
  1481.       *yyy = c & 0x07;
  1482.       *xxx = 0;
  1483.       check = 0;
  1484.       checkchk = 0;
  1485.       got_hdr = FALSE;
  1486.    }
  1487.  
  1488. /*--------------------------------------------------------------------*/
  1489. /*                        Handle data packets                         */
  1490. /*--------------------------------------------------------------------*/
  1491.    else {
  1492. get_data:
  1493.       if ( data == NULL )
  1494.       {
  1495.          printmsg(0,"grpack: Unexpected data packet!");
  1496.          received = 0;
  1497.          return(ERROR);
  1498.       }
  1499.  
  1500. /*--------------------------------------------------------------------*/
  1501. /*             Compute the size of the data block desired             */
  1502. /*--------------------------------------------------------------------*/
  1503.  
  1504.       total = 8 * (2 << grpkt[1]);
  1505.       if (total > pktsize)  /* Within the defined limits?          */
  1506.       {                       /* No --> Other system has bad header,
  1507.                                  or the header got corrupted         */
  1508.          printmsg(0,"grpack: Invalid packet size %d (%d)",
  1509.             total, (int) grpkt[1]);
  1510.          received = 0;
  1511.          got_hdr = FALSE;
  1512.          return(ERROR);
  1513.       }
  1514.  
  1515.       needed = total + HDRSIZE - received;
  1516.                                  /* Compute byte required to fill
  1517.                                     data buffer                      */
  1518.  
  1519. /*--------------------------------------------------------------------*/
  1520. /*     If we don't have enough data in the buffer, read some more     */
  1521. /*--------------------------------------------------------------------*/
  1522.  
  1523.       if ((needed > 0) &&
  1524.           (sread((char *) &grpkt[HDRSIZE+total-needed], needed , timeout) < (unsigned)needed))
  1525.          return(EMPTY);
  1526.  
  1527.       got_hdr = FALSE;           /* Must re-process header next pass */
  1528.  
  1529. /*--------------------------------------------------------------------*/
  1530. /*              Break packet header into various values               */
  1531. /*--------------------------------------------------------------------*/
  1532.  
  1533.       type = 0;
  1534.       c2 = grpkt[4];
  1535.       c = (unsigned char) (c2 & 0x3f);
  1536.       *xxx = c >> 3;
  1537.       *yyy = c & 0x07;
  1538.       i = grpkt[3];
  1539.       i = (i << 8) & 0xff00;
  1540.       check = grpkt[2];
  1541.       check = i | (check & 0xff);
  1542.       checkchk = checksum( (char *) grpkt + HDRSIZE , total);
  1543.       i = grpkt[4] | 0x80;
  1544.       i &= 0xff;
  1545.       checkchk = 0xaaaa - (checkchk ^ i);
  1546.       checkchk &= 0xffff;
  1547.       if (checkchk != check)
  1548.       {
  1549.          printmsg(4, "*** checksum error ***");
  1550.          memmove( grpkt, grpkt + HDRSIZE, total );
  1551.                               /* Save data so we can scan for sync   */
  1552.          received = total;    /* Note the amount of the data in buf  */
  1553.          return(ERROR);       /* Return to caller with error         */
  1554.       }
  1555.  
  1556. /*--------------------------------------------------------------------*/
  1557. /*    The checksum is correct, now determine the length of the        */
  1558. /*    data to return.                                                 */
  1559. /*--------------------------------------------------------------------*/
  1560.  
  1561.       *len = total;
  1562.  
  1563.       if (c2 & 0x40)
  1564.       {
  1565.          int ii;
  1566.          if ( grpkt[HDRSIZE] & 0x80 )
  1567.          {
  1568.             ii = (grpkt[HDRSIZE] & 0x7f) + ((grpkt[HDRSIZE+1] & 0xff) << 7);
  1569.             *len -= ii;
  1570.             memcpy(data, grpkt + HDRSIZE + 2, *len);
  1571.          }
  1572.          else {
  1573.             ii = (grpkt[HDRSIZE] & 0xff);
  1574.             *len -= ii;
  1575.             memcpy(data, grpkt + HDRSIZE + 1, *len);
  1576.          } /* else */
  1577.       }
  1578.       else
  1579.          memcpy( data, grpkt + HDRSIZE, *len);
  1580.    } /* else */
  1581.  
  1582. /*--------------------------------------------------------------------*/
  1583. /*           Announce what we got and return to the caller            */
  1584. /*--------------------------------------------------------------------*/
  1585.  
  1586.    received = 0;              /* Returning entire buffer, reset count */
  1587.    printmsg(5, "receive packet type %d, yyy=%d, xxx=%d, len=%d",
  1588.       type, *yyy, *xxx, *len);
  1589.  
  1590. #ifdef UDEBUG
  1591.    printmsg(13, " checksum rec=%04x comp=%04x\ndata=|%.*s|",
  1592.       check, checkchk, total, grpkt + HDRSIZE);
  1593. #endif
  1594.  
  1595.    return(type);
  1596.  
  1597. } /*grpack*/
  1598.  
  1599.  
  1600. /*
  1601.    c h e c k s u m
  1602. */
  1603.  
  1604. static unsigned int checksum(char *data, int len)
  1605. {
  1606.    int i, j;
  1607.    unsigned int tmp, chk1, chk2;
  1608.    chk1 = 0xffff;
  1609.    chk2 = 0;
  1610.    j = len;
  1611.    for (i = 0; i < len; i++) {
  1612.       if (chk1 & 0x8000) {
  1613.          chk1 <<= 1;
  1614.          chk1++;
  1615.       } else {
  1616.          chk1 <<= 1;
  1617.       }
  1618.       tmp = chk1;
  1619.       chk1 += (data[i] & 0xff);
  1620.       chk2 += chk1 ^ j;
  1621.       if ((chk1 & 0xffff) <= (tmp & 0xffff))
  1622.          chk1 ^= chk2;
  1623.       j--;
  1624.    }
  1625.    return(chk1 & 0xffff);
  1626.  
  1627. } /*checksum*/
  1628.